home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / mtools.lha / mtools-2.0.7 / init.c < prev    next >
C/C++ Source or Header  |  1992-09-10  |  8KB  |  364 lines

  1. /*
  2.  * Initialize an MSDOS diskette.  Read the boot sector, and switch to the
  3.  * proper floppy disk device to match the format on the disk.  Sets a bunch
  4.  * of global variables.  Returns 0 on success, or 1 on failure.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include "msdos.h"
  12.  
  13. #define FULL_CYL
  14. #define WORD(x) ((boot->x)[0] + ((boot->x)[1] << 8))
  15. #define DWORD(x) ((boot->x)[0] + ((boot->x)[1] << 8) + ((boot->x)[2] << 16) + ((boot->x)[3] << 24))
  16.  
  17. unsigned int num_clus;            /* total number of cluster */
  18. int num_fat;                /* the number of FAT tables */
  19. long disk_offset;            /* skip this many bytes */
  20. int fat_bits;                /* the FAT encoding scheme */
  21.  
  22. extern int fd, fat_len, dir_len, dir_start, clus_size, dir_dirty, disk_dirty;
  23. extern int fat_error, disk_size;
  24. extern long disk_current;
  25. extern char *mcwd;
  26. extern unsigned char *fat_buf, *disk_buf, *dir_buf;
  27. extern struct device devices[];
  28. static struct bootsector *read_boot();
  29.  
  30. int
  31. init(drive, mode)
  32. char drive;
  33. int mode;
  34. {
  35.     int fat_start, tracks, heads, sectors, old_dos;
  36.     char buf[256], *malloc(), *name, *expand();
  37.     void perror(), exit(), reset_chain(), free(), fat_read();
  38.     struct bootsector *boot;
  39.     struct device *dev;
  40.  
  41.     if (fd != -1) {
  42.         close(fd);
  43.         free((char *) fat_buf);
  44.         free((char *) disk_buf);
  45.         free((char *) dir_buf);
  46.     }
  47.                     /* check out the drive letter */
  48.     dev = devices;
  49.     while (dev->drive) {
  50.         if (dev->drive == drive)
  51.             break;
  52.         dev++;
  53.     }
  54.     if (!dev->drive) {
  55.         fprintf(stderr, "Drive '%c:' not supported\n", drive);
  56.         return(1);
  57.     }
  58.                     /* open the device */
  59.     while (dev->name) {
  60.         if (dev->drive != drive)
  61.             break;
  62.  
  63.         name = expand(dev->name);
  64.         if ((fd = open(name, mode | dev->mode)) < 0) {
  65.             sprintf(buf, "init: open \"%s\"", name);
  66.             perror(buf);
  67.             exit(1);
  68.         }
  69.                     /* lock the device on writes */
  70.         if (mode == 2 && lock_dev(fd)) {
  71.             fprintf(stderr, "Device \"%s\" is busy\n", dev->name);
  72.             exit(1);
  73.         }
  74.                     /* set default parameters, if needed */
  75.         if (dev->gioctl) {
  76.             if ((*(dev->gioctl)) (fd, dev->tracks, dev->heads, dev->sectors))
  77.                 goto try_again;
  78.         }
  79.                     /* read the boot sector */
  80.         disk_offset = dev->offset;
  81.         if ((boot = read_boot()) == NULL)
  82.             goto try_again;
  83.  
  84.         heads = WORD(nheads);
  85.         sectors = WORD(nsect);
  86.         if (heads && sectors)
  87.             tracks = WORD(psect) / (unsigned) (heads * sectors);
  88.  
  89.                     /* sanity checking */
  90.         old_dos = 0;
  91.         if (!heads || heads > 100 || !sectors || sectors > 500 || tracks > 5000 || !boot->clsiz) {
  92.             /*
  93.              * The above technique will fail on diskettes that
  94.              * have been formatted with very old MSDOS, so we
  95.              * resort to the old table-driven method using the
  96.              * media signature (first byte in FAT).
  97.              */
  98.             unsigned char temp[MSECTOR_SIZE];
  99.             if (read(fd, (char *) temp, MSECTOR_SIZE) != MSECTOR_SIZE)
  100.                 temp[0] = '0';
  101.  
  102.             switch (temp[0]) {
  103.                 case 0xfe:    /* 160k */
  104.                     tracks = 40;
  105.                     sectors = 8;
  106.                     heads = 1;
  107.                     dir_start = 3;
  108.                     dir_len = 4;
  109.                     clus_size = 1;
  110.                     fat_len = 1;
  111.                     num_clus = 313;
  112.                     break;
  113.                 case 0xfc:    /* 180k */
  114.                     tracks = 40;
  115.                     sectors = 9;
  116.                     heads = 1;
  117.                     dir_start = 5;
  118.                     dir_len = 4;
  119.                     clus_size = 1;
  120.                     fat_len = 2;
  121.                     num_clus = 351;
  122.                     break;
  123.                 case 0xff:    /* 320k */
  124.                     tracks = 40;
  125.                     sectors = 8;
  126.                     heads = 2;
  127.                     dir_start = 3;
  128.                     dir_len = 7;
  129.                     clus_size = 2;
  130.                     fat_len = 1;
  131.                     num_clus = 315;
  132.                     break;
  133.                 case 0xfd:    /* 360k */
  134.                     tracks = 40;
  135.                     sectors = 9;
  136.                     heads = 2;
  137.                     dir_start = 5;
  138.                     dir_len = 7;
  139.                     clus_size = 2;
  140.                     fat_len = 2;
  141.                     num_clus = 354;
  142.                     break;
  143.                 default:
  144.                     fprintf(stderr, "Probable non-MSDOS disk\n");
  145.                     close(fd);
  146.                     fd = -1;
  147.                     return(1);
  148.             }
  149.             fat_start = 1;
  150.             num_fat = 2;
  151.             old_dos = 1;
  152.         }
  153.                     /* check the parameters */
  154.         if (dev->tracks && !dev->gioctl) {
  155.             if (dev->tracks == tracks && dev->heads == heads && dev->sectors == sectors)
  156.                 break;
  157.         }
  158.         else
  159.             break;
  160.  
  161. try_again:    close(fd);
  162.         fd = -1;
  163.         dev++;
  164.     }
  165.     if (fd == -1) {
  166.         if (boot != NULL && dev->tracks)
  167.             fprintf(stderr, "No support for %d tracks, %d heads, %d sector diskettes\n", tracks, heads, sectors);
  168.         return(1);
  169.     }
  170.                     /* set new parameters, if needed */
  171.     if (dev->gioctl) {
  172.         if ((*(dev->gioctl)) (fd, tracks, heads, sectors)) {
  173.             fprintf(stderr, "Can't set disk parameters\n");
  174.             close(fd);
  175.             fd = -1;
  176.             return(1);
  177.         }
  178.     }
  179.  
  180.     /*
  181.      * all numbers are in sectors, except num_clus (which is in clusters)
  182.      */
  183.     if (!old_dos) {
  184.         clus_size = boot->clsiz;
  185.         fat_start = WORD(nrsvsect);
  186.         fat_len = WORD(fatlen);
  187.         dir_start = fat_start + (boot->nfat * fat_len);
  188.         dir_len = WORD(dirents) * MDIR_SIZE / (unsigned) MSECTOR_SIZE;
  189.         /*
  190.          * For DOS partitions > 32M
  191.          */
  192.         if (WORD(psect) == 0)
  193.             num_clus = (unsigned int) (DWORD(bigsect) - dir_start - dir_len) / clus_size;
  194.         else
  195.             num_clus = (unsigned int) (WORD(psect) - dir_start - dir_len) / clus_size;
  196.         num_fat = boot->nfat;
  197.     }
  198.                     /* more sanity checking */
  199.     if (clus_size * MSECTOR_SIZE > MAX_CLUSTER) {
  200.         fprintf(stderr, "Cluster size of %d is larger than max of %d\n", clus_size * MSECTOR_SIZE, MAX_CLUSTER);
  201.         close(fd);
  202.         fd = -1;
  203.         return(1);
  204.     }
  205.     if (!old_dos && WORD(secsiz) != MSECTOR_SIZE) {
  206.         fprintf(stderr, "Sector size of %d is not supported\n", WORD(secsiz));
  207.         close(fd);
  208.         fd = -1;
  209.         return(1);
  210.     }
  211.                     /* full cylinder buffering */
  212. #ifdef FULL_CYL
  213.     disk_size = (dev->tracks) ? (sectors * heads) : 1;
  214. #else /* FULL_CYL */
  215.     disk_size = (dev->tracks) ? sectors : 1;
  216. #endif /* FULL_CYL */
  217.  
  218.     disk_buf = (unsigned char *) malloc((unsigned int) disk_size * MSECTOR_SIZE);
  219.     if (disk_buf == NULL) {
  220.         perror("init: malloc");
  221.         exit(1);
  222.     }
  223.                     /* read the FAT sectors */
  224.     disk_current = -1000L;
  225.     disk_dirty = 0;
  226.     fat_error = 0;
  227.     fat_bits = dev->fat_bits;
  228.     fat_read(fat_start);
  229.                     /* set dir_chain[] to root directory */
  230.     dir_dirty = 0;
  231.     reset_chain(NEW);
  232.     return(0);
  233. }
  234.  
  235. /*
  236.  * Fix the info in the MCWD file to be a proper directory name.  Always
  237.  * has a leading separator.  Never has a trailing separator (unless it is
  238.  * the path itself).
  239.  */
  240.  
  241. char *
  242. fix_mcwd()
  243. {
  244.     FILE *fp;
  245.     struct stat sbuf;
  246.     char *s, *strcpy(), *strcat(), *mcwd_path, *getenv(), *strncpy();
  247.     char buf[BUFSIZ], *file, *expand();
  248.     static char ans[MAX_PATH];
  249.     long now, time();
  250.  
  251.     mcwd_path = getenv("MCWD");
  252.     if (mcwd_path == NULL || *mcwd_path == '\0')
  253.         mcwd_path = "$HOME/.mcwd";
  254.  
  255.     file = expand(mcwd_path);
  256.     if (stat(file, &sbuf) < 0)
  257.         return("A:/");
  258.     /*
  259.      * Ignore the info, if the file is more than 6 hours old
  260.      */
  261.     time(&now);
  262.     if (now - sbuf.st_mtime > 6 * 60 * 60) {
  263.         fprintf(stderr, "Warning: \"%s\" is out of date, contents ignored\n", file);
  264.         return("A:/");
  265.     }
  266.     
  267.     if (!(fp = fopen(file, "r")))
  268.         return("A:/");
  269.  
  270.     if (!fgets(buf, BUFSIZ, fp))
  271.         return("A:/");
  272.  
  273.     buf[strlen(buf) -1] = '\0';
  274.     fclose(fp);
  275.                     /* drive letter present? */
  276.     s = buf;
  277.     if (buf[0] && buf[1] == ':') {
  278.         strncpy(ans, buf, 2);
  279.         ans[2] = '\0';
  280.         s = &buf[2];
  281.     }
  282.     else 
  283.         strcpy(ans, "A:");
  284.                     /* add a leading separator */
  285.     if (*s != '/' && *s != '\\') {
  286.         strcat(ans, "/");
  287.         strcat(ans, s);
  288.     }
  289.     else
  290.         strcat(ans, s);
  291.                     /* translate to upper case */
  292.     for (s = ans; *s; ++s) {
  293.         if (islower(*s))
  294.             *s = toupper(*s);
  295.         if (*s == '\\')
  296.             *s = '/';
  297.     }
  298.                     /* if only drive, colon, & separator */
  299.     if (strlen(ans) == 3)
  300.         return(ans);
  301.                     /* zap the trailing separator */
  302.     if (*--s == '/')
  303.         *s = '\0';
  304.     return(ans);
  305. }
  306.  
  307. /*
  308.  * Read the boot sector.  We glean the disk parameters from this sector.
  309.  */
  310.  
  311. static struct bootsector *
  312. read_boot()
  313. {
  314.     long lseek();
  315.     static struct bootsector boot;
  316.  
  317.     if (lseek(fd, disk_offset, 0) < 0)
  318.         return(NULL);
  319.                     /* read the first sector */
  320.     if (read(fd, (char *) &boot, MSECTOR_SIZE) != MSECTOR_SIZE)
  321.         return(NULL);
  322.  
  323.     return(&boot);
  324. }
  325.  
  326. /*
  327.  * Create an advisory lock on the device to prevent concurrent writes.
  328.  * Uses either lockf, flock, or fcntl locking methods.  See the Makefile
  329.  * and the Configure files for how to specify the proper method.
  330.  */
  331.  
  332. static int
  333. lock_dev(fd)
  334. int fd;
  335. {
  336. #ifdef LOCKF
  337. #include <unistd.h>
  338.  
  339.     if (lockf(fd, F_TLOCK, 0) < 0)
  340.         return(1);
  341. #endif /* LOCKF */
  342.  
  343. #ifdef FLOCK
  344. #include <sys/file.h>
  345.  
  346.     if (flock(fd, LOCK_EX|LOCK_NB) < 0)
  347.         return(1);
  348. #endif /* FLOCK */
  349.  
  350. #ifdef FCNTL
  351. #include <fcntl.h>
  352.     struct flock flk;
  353.  
  354.     flk.l_type = F_WRLCK;
  355.     flk.l_whence = 0;
  356.     flk.l_start = 0L;
  357.     flk.l_len = 0L;
  358.  
  359.     if (fcntl(fd, F_SETLK, &flk) < 0)
  360.         return(1);
  361. #endif /* FCNTL */
  362.     return(0);
  363. }
  364.